package com.aios.util;

import java.io.IOException;

import javax.servlet.http.HttpServletResponse;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion;
import org.apache.http.StatusLine;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicStatusLine;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.util.EntityUtils;
import org.apache.log4j.Logger;

public class HttpClientAdaptor extends DefaultHttpClient {

	private static Logger logger = Logger.getLogger("com.aios.util.HttpClientAdaptor");

	private HttpHost targetHost;
	private BasicHttpContext localcontext;

	public HttpClientAdaptor() {
		super();
	}

	public HttpClientAdaptor(String ipAddress, String port, String scheme, String username, String password, boolean authCache) {
		super();
		targetHost = new HttpHost(ipAddress, new Integer(port), scheme);
		this.getCredentialsProvider().setCredentials(
                new AuthScope(targetHost.getHostName(), targetHost.getPort()),
                new UsernamePasswordCredentials(username, password));

		if(authCache) {
			createAuthCache(targetHost);
		}
	}

	public HttpClientAdaptor(String host, String port, String username, String password, boolean authCache) {
		
		super();
		//System.out.println("port:"+port);
		if(port.equals(AiosAccessUtil.DEFAULT_HTTP_PORT)){
			targetHost = new HttpHost(host);
		} else {
			targetHost = new HttpHost(host, new Integer(port), AiosAccessUtil.PROTOCOL);
		}

		this.getCredentialsProvider().setCredentials(
                new AuthScope(targetHost.getHostName(), targetHost.getPort()),
                new UsernamePasswordCredentials(username, password));

		if(authCache) {
			createAuthCache(targetHost);
		}
	}

	private void createAuthCache(HttpHost targetHost) {
        // Create AuthCache instance
        AuthCache authCache = new BasicAuthCache();
        BasicScheme basicAuth = new BasicScheme();
        authCache.put(targetHost, basicAuth);

        // Add AuthCache to the execution context
        BasicHttpContext localcontext = new BasicHttpContext();
        localcontext.setAttribute(ClientContext.AUTH_CACHE, authCache);
	}

	public HttpClientResponse execute(String uri) throws IOException {

		//example-cgi?param1=value1&param2=value2
		//logger.info("NB202 request:" + uri);
		//System.out.println("Execute:" + uri);
		HttpGet httpget = new HttpGet(uri);
		HttpClientResponse resp = new HttpClientResponse();
		try {
			HttpResponse response;
			
			if (localcontext != null) {
				response = this.execute(targetHost, httpget, localcontext);
			} else {
				response = this.execute(targetHost, httpget);
			}
			HttpEntity entity = response.getEntity();
			resp.setStatusLine(response.getStatusLine());

			if (entity != null) {
				resp.setResponseText(FileUtil.convertStreamToString(entity.getContent()));
			}

			EntityUtils.consume(entity);
			this.getConnectionManager().shutdown();
			
		} catch(ClientProtocolException e) {
        	logger.error(e);
        	logger.error(uri);
        	resp.setStatusLine(new BasicStatusLine(new ProtocolVersion(targetHost.getSchemeName(), 1, 1), HttpServletResponse.SC_BAD_REQUEST, "CONNECTION STABLISHMENT FAULT"));
        } catch(IOException e) {
        	//System.out.println("Network Connection Error, Please check your connection...");
        	logger.error(e);
        	//System.out.println(e.getMessage());
        	resp.setStatusLine(new BasicStatusLine(new ProtocolVersion(targetHost.getSchemeName(), 1, 1), HttpServletResponse.SC_NOT_FOUND, "IO ERROR"));
        } catch(NullPointerException e) {
        	resp.setStatusLine(new BasicStatusLine(new ProtocolVersion(targetHost.getSchemeName(), 1, 1), HttpServletResponse.SC_NOT_FOUND, "NULL REFERENCE"));
        	logger.error(e);
        } catch(Exception e) {
        	logger.error(e);
        } finally {
            this.getConnectionManager().shutdown();
        }

		return resp;

	}

	public static HttpClientResponse execute(String ipAddress, int port, String scheme, String uri) {

		HttpClient httpclient = new DefaultHttpClient();
		HttpClientResponse resp = new HttpClientAdaptor().new HttpClientResponse();

        try {

        	HttpHost targetHost = new HttpHost(ipAddress, port, scheme);

        	HttpGet httpget = new HttpGet(uri);
        	HttpResponse response = httpclient.execute(targetHost, httpget);
        	HttpEntity entity = response.getEntity();

            resp.setStatusLine(response.getStatusLine());

            if (entity != null) {
            	resp.setResponseText(FileUtil.convertStreamToString(entity.getContent()));
            }

            EntityUtils.consume(entity);


        } catch(ClientProtocolException e) {
        	e.printStackTrace();
        	logger.error(e);
        	resp.setStatusLine(new BasicStatusLine(new ProtocolVersion(scheme, 1, 1), HttpServletResponse.SC_BAD_REQUEST, "CONNECTION STABLISHMENT FAULT"));
        } catch(IOException e) {
        	e.printStackTrace();
        	logger.error(e);
        	resp.setStatusLine(new BasicStatusLine(new ProtocolVersion(scheme, 1, 1), HttpServletResponse.SC_NOT_FOUND, "IO ERROR"));
        } finally {
            httpclient.getConnectionManager().shutdown();
        }

        return resp;
	}

	//inner class
	public class HttpClientResponse {

		private StatusLine statusLine;
		private String responseText = "";

		public HttpClientResponse() {

		}

		public HttpClientResponse(StatusLine statusLine, String responseText) {
			this.statusLine = statusLine;
			this.responseText = responseText;
		}

		public StatusLine getStatusLine() {
			return statusLine;
		}

		public void setStatusLine(StatusLine statusLine) {
			this.statusLine = statusLine;
		}

		public String getResponseText() {
			return responseText;
		}

		public void setResponseText(String responseText) {
			this.responseText = responseText;
		}

	}

}
